package com.yzi.core.schedule
{
	import com.yzi.core.thread.IRunnable;
	import com.yzi.core.thread.Thread;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.ProgressEvent;
	
	public class Schedule extends Thread implements ITask, IEventDispatcher
	{
		private var m_dispatcher:IEventDispatcher;
		private var m_progress:uint;
		private var m_worker:IWorker;
		private var m_taskList:Vector.<ITask>;
		private var m_report:Report;
		private var m_reportList:Vector.<IReport>;
		
		public function Schedule($worker:IWorker)
		{
			//super($runnable);
			m_worker = $worker;
			init();
		}
		
		private function init(): void
		{
			m_dispatcher = new EventDispatcher(this);
			m_taskList = new Vector.<ITask>();
			m_reportList = new Vector.<IReport>();
			m_report = new Report();
			
			m_report.SetResult(m_reportList);
			m_progress = 0;
			
			m_worker.addEventListener(Event.COMPLETE, Next);
			this.addEventListener(Event.COMPLETE, Next);
		}
		
		public function Add($task:ITask): void
		{
			m_taskList.push($task);
			m_reportList.push($task.GetReport());
		}
		
		public function RemoveAt($index:uint): void
		{
			m_taskList.splice($index, 1);
			m_reportList.splice($index, 1);
		}
		
		public function Next($event:Event = null): void { Start(); }
		
		public function Reset(): void
		{
			m_progress = 0;
			m_taskList.length = 0;
			m_reportList.length = 0;
		}
		
		override public function Destory():void
		{
			m_worker.removeEventListener(Event.COMPLETE, Next);
			if(m_dispatcher) removeEventListener(Event.COMPLETE, m_report.Notify);
			
			var taskListLength:uint = m_taskList.length;
			for(var i:int = 0; i < taskListLength; ++i)
			{
				m_taskList[0].Stop();
				m_taskList[0].Destory();
				m_taskList[0] = null;
			}
			
			if(m_reportList) m_reportList.length = 0;
			m_reportList = null;
			m_report.Destory();
			
			m_dispatcher = null;
			super.Destory();
		}
		
		override public function Run():void
		{
			if(m_progress >= m_taskList.length) {
				dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, m_progress, m_taskList.length));
				dispatchEvent(new Event(Event.COMPLETE));
				
				return;
			}
			
			m_worker.Execute(m_taskList[m_progress]);
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, m_progress, m_taskList.length));
			m_progress++;
		}
		
		public function GetAt($index:int): ITask
		{
			if($index < 0 || m_taskList.indexOf($index) < 0) throw new Error("Out of range");
			return m_taskList[$index];
		}
		
		public function GetIndex($task:ITask): int { return m_taskList.indexOf($task); }
		
		public function GetReport():IReport { return m_report; }
		
		public function GetProgress(): uint { return m_progress; }
		
		public function GetLength(): uint { return m_taskList.length; }
		
		public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false): void
		{
			m_dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			m_dispatcher.removeEventListener(type, listener, useCapture);
		}
		
		public function dispatchEvent(event:Event):Boolean
		{
			return m_dispatcher.dispatchEvent(event);
		}
		
		public function hasEventListener(type:String):Boolean
		{
			return m_dispatcher.hasEventListener(type);
		}
		
		public function willTrigger(type:String):Boolean
		{
			return m_dispatcher.willTrigger(type);
		}
	}
}